﻿using System;

namespace MathService.Vectors
{
    public partial struct Vector3D
    {
        #region Вектор на число

        public static Vector3D operator +(Vector3D V, double x) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }
        public static Vector3D operator +(double x, Vector3D V) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }

        public static Vector3D operator -(Vector3D V, double x) { return new Vector3D(V.f_X - x, V.f_Y - x, V.f_Z - x); }
        public static Vector3D operator -(double x, Vector3D V) { return new Vector3D(x - V.f_X, x - V.f_Y, x - V.f_Z); }

        public static Vector3D operator *(Vector3D V, double x) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }
        public static Vector3D operator *(double x, Vector3D V) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }

        public static Vector3D operator /(Vector3D V, double x) { return new Vector3D(V.f_X / x, V.f_Y / x, V.f_Z / x); }
        public static Vector3D operator /(double x, Vector3D V) { return new Vector3D(x / V.f_X, x / V.f_Y, x / V.f_Z); }


        public static Vector3D operator +(Vector3D V, float x) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }
        public static Vector3D operator +(float x, Vector3D V) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }

        public static Vector3D operator -(Vector3D V, float x) { return new Vector3D(V.f_X - x, V.f_Y - x, V.f_Z - x); }
        public static Vector3D operator -(float x, Vector3D V) { return new Vector3D(x - V.f_X, x - V.f_Y, x - V.f_Z); }

        public static Vector3D operator *(Vector3D V, float x) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }
        public static Vector3D operator *(float x, Vector3D V) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }

        public static Vector3D operator /(Vector3D V, float x) { return new Vector3D(V.f_X / x, V.f_Y / x, V.f_Z / x); }
        public static Vector3D operator /(float x, Vector3D V) { return new Vector3D(x / V.f_X, x / V.f_Y, x / V.f_Z); }


        public static Vector3D operator +(Vector3D V, int x) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }
        public static Vector3D operator +(int x, Vector3D V) { return new Vector3D(V.f_X + x, V.f_Y + x, V.f_Z + x); }

        public static Vector3D operator -(Vector3D V, int x) { return new Vector3D(V.f_X - x, V.f_Y - x, V.f_Z - x); }
        public static Vector3D operator -(int x, Vector3D V) { return new Vector3D(x - V.f_X, x - V.f_Y, x - V.f_Z); }

        public static Vector3D operator *(Vector3D V, int x) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }
        public static Vector3D operator *(int x, Vector3D V) { return new Vector3D(V.f_X * x, V.f_Y * x, V.f_Z * x); }

        public static Vector3D operator /(Vector3D V, int x) { return new Vector3D(V.f_X / x, V.f_Y / x, V.f_Z / x); }
        public static Vector3D operator /(int x, Vector3D V) { return new Vector3D(x / V.f_X, x / V.f_Y, x / V.f_Z); }

        #endregion

        #region Операции над двумя векторами

        public static Vector3D operator +(Vector3D A, Vector3D B)
        {
            return new Vector3D(A.f_X + B.f_X, A.f_Y + B.f_Y, A.f_Z + B.f_Z);
        }

        public static Vector3D operator -(Vector3D A, Vector3D B)
        {
            return new Vector3D(A.f_X - B.f_X, A.f_Y - B.f_Y, A.f_Z - B.f_Z);
        }

        /// <summary>Скалярное произведение векторов</summary>
        /// <param name="A">Первый вектор-множитель</param>
        /// <param name="B">Второй вектор-множитель</param>
        /// <returns>Число - скалярное произведение векторов</returns>
        public static double operator *(Vector3D A, Vector3D B) { return A.Product_Scalar(B); }

        //public static Vector3D operator /(Vector3D A, Vector3D B) { return A * B.GetInverse(); }

        /// <summary>Угол между векторами</summary>
        /// <param name="A">Вектор 1</param>
        /// <param name="B">Вектор 2</param>
        /// <returns>Угол между вектором А и вектором В в пространстве</returns>
        public static SpaceAngle operator ^(Vector3D A, Vector3D B) { return A.GetAngle(B); }

        /// <summary>Проверка на параллельность</summary>
        /// <param name="A">Вектор 1</param><param name="B">Вектор 2</param>
        /// <returns>Истина, если вектора параллельны</returns>
        public static bool operator |(Vector3D A, Vector3D B) { return Math.Abs((A * B) / (A.R * B.R) - 1) < double.Epsilon; }

        /// <summary>Проверка на ортогональность</summary>
        /// <param name="A">Вектор 1</param><param name="B">Вектор 2</param>
        /// <returns>Истина, если вектор 1 ортогонален вектору 2</returns>
        public static bool operator &(Vector3D A, Vector3D B) { return Math.Abs((A * B) / (A.R * B.R)) < double.Epsilon; }

        /// <summary>Проекция вектора A на вектор B</summary>
        /// <param name="A">Проецируемый вектор</param>
        /// <param name="B">Вектор, на который производится проекция</param>
        /// <returns>Проекция вектора А на вектор В</returns>
        public static double operator %(Vector3D A, Vector3D B) { return A.GetProjectionTo(B); }

        public static double operator %(Vector3D Vector, SpaceAngle Direction) { return Vector.GetProjectionTo(Direction); }
        public static double operator %(Vector3D Vector, Basis3D b) { return Vector.InBasis(b); }

        #endregion

        #region Операторы преобразований

        public static implicit operator double(Vector3D V) { return V.R; }

        public static implicit operator SpaceAngle(Vector3D V) { return V.Angle; }

        public static explicit operator Vector3D(SpaceAngle Angle) { return new Vector3D(1, Angle); }

        #endregion
    }
}
